/* ==================================================================   
 * Created [2009-4-27 下午11:32:55] by Jon.King 
 * ==================================================================  
 * TSS 
 * ================================================================== 
 * mailTo:jinpujun@hotmail.com
 * Copyright (c) Jon.King, 2009-2012 
 * ================================================================== 
 */

package com.jinhe.tss.cms.workflow;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;

import com.jinhe.tss.cms.CMSConstants;
import com.jinhe.tss.cms.workflow.WorkFlowNode.WorkerFlowButton;
import com.jinhe.tss.core.cachepool.CacheManager;
import com.jinhe.tss.core.cachepool.Cacheable;
import com.jinhe.tss.core.cachepool.CacheableKey;
import com.jinhe.tss.core.cachepool.IPool;
import com.jinhe.tss.core.exception.BusinessException;
import com.jinhe.tss.core.util.EasyUtils;
import com.jinhe.tss.core.util.FileHelper;
import com.jinhe.tss.core.util.URLUtil;
import com.jinhe.tss.core.util.XMLDocUtil;

/**
 * <p> WorkFlowOperator.java </p>
 * 工作流操作对象
 */
public class WorkFlowManager {
	
	static final String WORKFLOWS_CACHE_KEY = "workflows_info";
    
    static IPool pool = CacheManager.getInstance().getCachePool(WORKFLOWS_CACHE_KEY);
    
    static Document templateDoc ;

    private WorkFlowManager(){
    	templateDoc = XMLDocUtil.createDoc(CMSConstants.WORKFLOW_TEMPLATE_PATH);
        init();
    }
    
    private static WorkFlowManager manager;
    
    public static WorkFlowManager getInstance(){
        if(manager == null) {
            manager = new WorkFlowManager();
        }
        return manager;
    }
    
    private void init() {
        List<Element> workflowElementList = XMLDocUtil.selectNodes(templateDoc, "//workflow");
        for ( Element workflowElement : workflowElementList ) {
            String code = workflowElement.elementText("code");
			String name = workflowElement.elementText("name");
			WorkFlow workFlow = new WorkFlow(code, name);
            
			List<Element> stepElementList = XMLDocUtil.selectNodes(workflowElement, "//flow");
            for ( Element stepElement : stepElementList ) {
                String status = stepElement.elementText("status");
				String stepName = stepElement.elementText("name");
				WorkFlowNode workFlowStep = new WorkFlowNode(status, stepName);
				
                if (stepElement.element("next") != null) {
                    Element next = stepElement.element("next");
                    
                    WorkerFlowButton wfButton = new WorkerFlowButton(next.elementText("status"), next.elementText("button"));
					workFlowStep.setNextButton(wfButton);
                }
                if (stepElement.element("preview") != null) {
                    Element preview = stepElement.element("preview");
                    
                    WorkerFlowButton wfButton = new WorkerFlowButton(preview.elementText("status"), preview.elementText("button"));
					workFlowStep.setPreviewButton(wfButton);
                }
                
                workFlow.getFlowStepsMap().put(workFlowStep.getStatus(), workFlowStep);
            }
            
            pool.putObject(workFlow.getCode(), workFlow);
        }
    }
    
	/**
	 * 获取文章工作量流列表
	 * @return
	 */
	public List<CacheableKey> getWorkFlowCodes() {
		return pool.listKeys();
	}
    
    /**
     * 将所有工作流拼成下拉列表
     */
    public String[] getWorkFlowCodeAndNames() {
        List<Cacheable> list = pool.listItems();
        List<WorkFlow> workFlowList = new ArrayList<WorkFlow>();
        for( Cacheable temp : list ){
            workFlowList.add( (WorkFlow) temp.getValue() );
        }
        return EasyUtils.generateComboedit(workFlowList, "code", "name", "|");
    }
    
    /**
     *  将指定工作流的步骤拼成下拉列表
     */
    public String[] getFlowStepStatusAndNames(Integer workflowId){
        Map<Integer, WorkFlowNode> map = getWorkFlow(workflowId).getFlowStepsMap();
        List<WorkFlowNode> nodeList = new ArrayList<WorkFlowNode>(map.values());
        return EasyUtils.generateComboedit(nodeList, "status", "name", "|");
    }

	/**
	 * 根据工作流ID获取工作流对象
	 * @param workflowId
	 * @return
	 */
	public WorkFlow getWorkFlow(Integer workflowId) {
        Cacheable c = pool.getObject(workflowId);
        if (c == null) {
            throw new BusinessException("未找到id为：" + workflowId + "的文章工作流 ");
        }
        
		return (WorkFlow) c.getValue();
	}

	/**
	 * 获取文章流步骤
	 * @param workflowId 工作流
	 * @param status     工作流步骤状态
	 * @return
	 */
	public WorkFlowNode getWorkFlowNode(Integer workflowId, Integer status) {
		WorkFlow wf = getWorkFlow(workflowId);
		Object step = wf.getFlowStepsMap().get(status);
        if (step == null) {
			throw new BusinessException("未找到文章流步骤");
        }

        return (WorkFlowNode) step;
	}

	/**
	 * 获取文章流步骤的前进按钮
	 * @param workflowId
	 * @param status
	 * @return
	 */
	public WorkerFlowButton getNextButton(Integer workflowId, Integer status) {
		return getWorkFlowNode(workflowId, status).getNextButton();
	}

	/**
	 * 获取文章流步骤的退回按钮
	 * @param workflowId
	 * @param status
	 * @return
	 */
	public WorkerFlowButton getPreviewButton(Integer workflowId, Integer status) {
		return getWorkFlowNode(workflowId, status).getPreviewButton();
	}

	/**
	 * 获取文章流步骤的退回按钮列表
	 * 
	 * @param workflowId
	 * @param status
	 * @return
	 */
	public  Map<Integer, WorkerFlowButton> getPreviews(Integer workflowId, Integer status) {
		WorkFlow wf = getWorkFlow(workflowId);
		WorkFlowNode wfNode = wf.getFlowStepsMap().get(status);
        
        Map<Integer, WorkerFlowButton> previewButtons = new LinkedHashMap<Integer, WorkerFlowButton>();
        while(wfNode != null && wfNode.getPreviewButton() != null){
            Integer preStatus = wfNode.getPreviewButton().getStatus();
            previewButtons.put(preStatus, wfNode.getPreviewButton());
            wfNode = (WorkFlowNode) wf.getFlowStepsMap().get((preStatus));
        }
		return previewButtons;
	}

	/**
	 * 导入工作流
	 * @param file
	 * @param name
	 * @return
	 */
	public void importWorkFlow(File file, String name) {
		// 判断工作流名称是否重复
		List<Element> workflowList = XMLDocUtil.selectNodes(templateDoc, "//workflow");
        for ( Element workflow : workflowList ) {
        	String nodeName = workflow.elementText("name");
			if(nodeName.equals(name)) {
				throw new BusinessException("工作流名称已存在！请更换名称！");
			}
        }
        
        Document importDoc = XMLDocUtil.createDocByAbsolutePath(file.getPath());
		Element newWorkFlow = importDoc.getRootElement();
 
		Element rootElement = templateDoc.getRootElement();
		rootElement.add(newWorkFlow);
		
		updateDocment(templateDoc);
	}

	private static void updateDocment(Document doc) {
        String path = URLUtil.getResourceFileUrl(CMSConstants.WORKFLOW_TEMPLATE_PATH).getPath();
		FileHelper.writeXMLDoc(doc, path);
        manager = null; // 重新载入
	}

	/**
	 * 删除工作流
	 * @param code
	 * @return
	 */
	public  boolean deleteWorkFlow(Integer code) {
		Node node = templateDoc.selectSingleNode("/workflows/workflow[code/text()='" + code + "']");
		if (node == null) {
			throw new BusinessException("未找到要删除的工作流!");
		}
		
        node.detach();
        
        updateDocment(templateDoc);
		return true;
	}

	/**
	 * 获取工作流模板
	 */
	public static String getModel() {
		return XMLDocUtil.createDoc("workflow/WorkFlowTemplate.xml").asXML();
	}
}